package com.zhx.common.websocket.handle;

import cn.hutool.core.net.url.UrlBuilder;
import com.zhx.common.websocket.util.NettyUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.HttpRequest;
import org.apache.commons.lang3.StringUtils;

import java.net.InetSocketAddress;
import java.util.Optional;

/**
 * 入站处理器通常是 ChannelInboundHandlerAdapter 的子类，主要用来读取客户端数据，写回结果
 *
 * 在握手的时候，从http的请求体中，获取到url再拿到参数
 * 获取请求头中的token,还可以获取请求头中的ip
 */
public class MyHeaderCollectHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        if (msg instanceof HttpRequest) {
            HttpRequest request = (HttpRequest) msg;
            UrlBuilder urlBuilder = UrlBuilder.ofHttp(request.getUri());

            //获取token参数 -> ws://127.0.0.1:8080?token=...
            Optional<String> token = Optional.of(urlBuilder)
                    .map(UrlBuilder::getQuery)
                    .map(k -> k.get("token"))
                    .map(CharSequence::toString);

            //token如果存在
            token.ifPresent(s -> NettyUtil.setAttr(ctx.channel(), NettyUtil.TOKEN, s));

            //移除后面拼接的token参数
            request.setUri(urlBuilder.getPathStr().toString());

            //如果用nginx代理，获取真实ip
            String ip = request.headers().get("X-Real-IP");
            //如果ip为空，则获取本机ip
            if(StringUtils.isBlank(ip)){
                InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
                ip = address.getAddress().getHostAddress();
            }

            /**
             * 之后协议升级后，请求就不会再走这个处理器了，所以我们的ip需要保存起来。
             * 正好channel其实有个附件功能，我们可以直接把ip作为附件保存进channel。
             * 之后每次的websocket请求，都用的是同一个channel，从里面取ip就好了。
             */
            //保存到channel的属性中
            NettyUtil.setAttr(ctx.channel(), NettyUtil.IP, ip);

            //移除自己
            ctx.pipeline().remove(this);
        }
        //触发后续处理器
        ctx.fireChannelRead(msg);
    }
}
